home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 24
/
Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso
/
Aminet
/
comm
/
mail
/
Mutt089src.lha
/
Mutt-0.89i-AMIGA
/
src
/
rfc2047.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-01-28
|
7KB
|
360 lines
/*
* Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "mutt.h"
#include "mime.h"
#include "rfc2047.h"
#include <ctype.h>
#include <string.h>
typedef void encode_t (char *, unsigned char *, size_t);
extern char *tspecials;
extern char B64Chars[];
static void q_encode_string (char *d, unsigned char *s, size_t len)
{
char charset[SHORT_STRING];
int cslen;
int wordlen;
char *wptr = d;
snprintf (charset, sizeof (charset), "=?%s?Q?",
strcasecmp ("us-ascii", charset) == 0 ? "unknown-8bit" : Charset);
cslen = strlen (charset);
/*
* Hack to pull the Re: and Fwd: out of the encoded word for better
* handling by agents which do not support RFC2047.
*/
if (strncasecmp ("re: ", (char *) s, 4) == 0)
{
strncpy (wptr, (char *) s, 4);
wptr += 4;
s += 4;
}
else if (strncasecmp ("fwd: ", (char *) s, 5) == 0)
{
strncpy (wptr, (char *) s, 5);
wptr += 5;
s += 5;
}
strcpy (wptr, charset);
wptr += cslen;
wordlen = cslen;
while (*s)
{
if (wordlen >= 72)
{
strcpy(wptr, "?=\n ");
wptr += 4;
strcpy(wptr, charset);
wptr += cslen;
wordlen = cslen;
}
if (*s == ' ')
{
*wptr++ = '_';
wordlen++;
}
else if (*s & 0x80 || (strchr (tspecials, *s) != NULL))
{
if (wordlen >= 70)
{
strcpy (wptr, "?=\n ");
wptr += 4;
strcpy (wptr, charset);
wptr += cslen;
wordlen = cslen;
}
sprintf (wptr, "=%2X", *s);
wptr += 3;
wordlen += 3;
}
else
{
*wptr++ = *s;
wordlen++;
}
s++;
}
strcpy (wptr, "?=");
}
static void b_encode_string (char *d, unsigned char *s, size_t len)
{
char charset[SHORT_STRING];
char *wptr = d;
int cslen;
int wordlen;
snprintf (charset, sizeof (charset), "=?%s?B?", Charset);
cslen = strlen (charset);
strcpy (wptr, charset);
wptr += cslen;
wordlen = cslen;
while (*s)
{
if (wordlen >= 71)
{
strcpy(wptr, "?=\n ");
wptr += 4;
strcpy(wptr, charset);
wptr += cslen;
wordlen = cslen;
}
*wptr++ = B64Chars[ (*s >> 2) & 0x3f ];
*wptr++ = B64Chars[ ((*s & 0x3) << 4) | ((*(s+1) >> 4) & 0xf) ];
s++;
if (*s)
{
*wptr++ = B64Chars[ ((*s & 0xf) << 2) | ((*(s+1) >> 6) & 0x3) ];
s++;
if (*s)
{
*wptr++ = B64Chars[ *s & 0x3f ];
s++;
}
else
*wptr++ = '=';
}
else
{
*wptr++ = '=';
*wptr++ = '=';
}
wordlen += 4;
}
strcpy(wptr, "?=");
}
void rfc2047_encode_string (char *d, unsigned char *s, size_t l)
{
int count = 0;
int len;
unsigned char *p = s;
encode_t *encoder;
/* First check to see if there are any 8-bit characters */
while (*p)
{
if (*p & 0x80) count++;
p++;
}
if (!count)
{
strfcpy (d, (char *)s, l);
return;
}
if (strcasecmp("us-ascii", Charset) == 0 ||
strncasecmp("iso-8859", Charset, 8) == 0)
encoder = q_encode_string;
else
{
/* figure out which encoding generates the most compact representation */
len = strlen ((char *) s);
if ((count * 2) + len <= (4 * len) / 3)
encoder = q_encode_string;
else
encoder = b_encode_string;
}
(*encoder)(d, s, l);
}
void rfc2047_encode_adrlist (ADDRESS *addr)
{
ADDRESS *ptr = addr;
char buffer[STRING];
while (ptr)
{
if (ptr->personal)
{
rfc2047_encode_string (buffer, (unsigned char *)ptr->personal, sizeof (buffer));
safe_free ((void **)&ptr->personal);
ptr->personal = safe_strdup (buffer);
}
ptr = ptr->next;
}
}
static int rfc2047_decode_word (char *d, const char *s, size_t len)
{
char *p = safe_strdup (s);
char *pp = p;
char *pd = d;
int enc = 0, filter = 0, count = 0, c1, c2, c3, c4;
while ((pp = strtok (pp, "?")) != NULL)
{
count++;
switch (count)
{
case 2:
if (strcasecmp (pp, Charset) != 0)
filter = 1;
break;
case 3:
if (toupper (*pp) == 'Q')
enc = ENCQUOTEDPRINTABLE;
else if (toupper (*pp) == 'B')
enc = ENCBASE64;
else
return (-1);
break;
case 4:
if (enc == ENCQUOTEDPRINTABLE)
{
while (*pp && len > 0)
{
if (*pp == '_')
{
*pd++ = ' ';
len--;
}
else if (*pp == '=')
{
*pd++ = (hexval(pp[1]) << 4) | hexval(pp[2]);
len--;
pp += 2;
}
else
{
*pd++ = *pp;
len--;
}
pp++;
}
*pd = 0;
}
else if (enc == ENCBASE64)
{
while (*pp && len > 0)
{
c1 = Index_64[(int) pp[0]];
c2 = Index_64[(int) pp[1]];
*pd++ = (c1 << 2) | ((c2 >> 4) & 0x3);
if (--len == 0) break;
if (pp[2] == '=') break;
c3 = Index_64[(int) pp[2]];
*pd++ = ((c2 & 0xf) << 4) | ((c3 >> 2) & 0xf);
if (--len == 0)
break;
if (pp[3] == '=')
break;
c4 = Index_64[(int) pp[3]];
*pd++ = ((c3 & 0x3) << 6) | c4;
if (--len == 0)
break;
pp += 4;
}
*pd = 0;
}
break;
}
pp = 0;
}
safe_free ((void **) &p);
if (filter)
{
pd = d;
while (*pd)
{
if (!IsPrint ((unsigned char) *pd))
*pd = '?';
pd++;
}
}
return (0);
}
/* try to decode anything that looks like a valid RFC2047 encoded
* header field, ignoring RFC822 parsing rules
*/
void rfc2047_decode (char *d, const char *s, size_t dlen)
{
const char *p, *q;
size_t n;
int found_encoded = 0;
dlen--; /* save room for the terminal nul */
while (*s && dlen > 0)
{
if ((p = strstr (s, "=?")) == NULL ||
(q = strchr (p + 2, '?')) == NULL ||
(q = strchr (q + 1, '?')) == NULL ||
(q = strstr (q + 1, "?=")) == NULL)
{
/* no encoded words */
if (d != s)
strfcpy (d, s, dlen + 1);
return;
}
if (p != s)
{
n = (size_t) (p - s);
/* ignore spaces between encoded words */
if (!found_encoded || strspn (s, " \t") != n)
{
if (n > dlen)
n = dlen;
if (d != s)
memcpy (d, s, n);
d += n;
dlen -= n;
}
}
rfc2047_decode_word (d, p, dlen);
found_encoded = 1;
s = q + 2;
n = strlen (d);
dlen -= n;
d += n;
}
*d = 0;
}
void rfc2047_decode_adrlist (ADDRESS *a)
{
while (a)
{
if (a->personal && strstr (a->personal, "=?") != NULL)
rfc2047_decode (a->personal, a->personal, strlen (a->personal) + 1);
a = a->next;
}
}